package com.pan.download4.driver;

import com.pan.crawler.Directory;
import com.pan.crawler.Page;
import com.pan.crawler.impl.DirectoryImpl;
import com.pan.crawler.impl.PageImpl;
import com.pan.download4.build.PanBuilder;
import com.pan.download4.ctrl.TaskPublishSynchronized;
import com.pan.download4.ctrl.WriteChapterSynchronized;
import com.pan.entity.BookDirectory;
import com.pan.entity.Chapter;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class Driver {
    private TaskPublishSynchronized taskPublishSynchronized;
    private WriteChapterSynchronized writeChapterSynchronized;
    private Class pageClass;
    private Class directoryClass;
    private int threadCount;
    private ThreadPoolExecutor threadPoolExecutor;
    public Driver(){
        this.pageClass = PageImpl.class;
        this.directoryClass = DirectoryImpl.class;
        this.threadCount = 10;
        threadPoolExecutor = new ThreadPoolExecutor(threadCount,
                threadCount,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }
    public Driver(Class pageClass,Class directoryClass,int threadCount){
        if (!Page.class.isAssignableFrom(pageClass) ||
            !Directory.class.isAssignableFrom(directoryClass)){
            throw new RuntimeException("传入的Class没有实现接口");
        }
        this.pageClass = pageClass;
        this.directoryClass = directoryClass;
        this.threadCount = threadCount;
        threadPoolExecutor = new ThreadPoolExecutor(threadCount,
                threadCount,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    public Driver(String url,int threadCount){
        this(PanBuilder.getPageClass(url),PanBuilder.getDirectoryClass(url),threadCount);
    }


    public void run(String url){
        this.run(url,0);
    }
    public void run(String url,int intervalTime){
        String dirPath = System.getProperty("user.dir")+"\\story";
        this.run(url,dirPath,intervalTime);
    }
    /**
     *
     * @param url
     * @param saveDirPath
     * @param intervalTime MILLISECONDS
     */
    public void run(String url,String saveDirPath,int intervalTime){
        Directory directory;
        try {
            directory = (Directory) directoryClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        BookDirectory bookDirectory = directory.get(url);
        this.taskPublishSynchronized = new TaskPublishSynchronized(bookDirectory.getChapterList(),intervalTime);
        this.writeChapterSynchronized = new WriteChapterSynchronized(saveDirPath,bookDirectory.getBookName());
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            threadPoolExecutor.execute(()->{
                Page page;
                try {
                    page = (Page) pageClass.newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
                for (;;) {
                    Chapter task = this.taskPublishSynchronized.getTask();
                    if (task == null) break;
                    String context = "";
                    try {
                        context  = page.get(task);
                    }catch (Exception e){
                        e.printStackTrace();
                        System.out.println("爬取错误取消任务："+task.toString());
                        try {
                            this.taskPublishSynchronized.cancelTask(task);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                        continue;
                    }
                    this.writeChapterSynchronized.write(task,context);
                    System.out.println(task.toString()+" 下载完成！");
                }
                page.close();
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        threadPoolExecutor.shutdown();
        writeChapterSynchronized.close();
        System.out.println(bookDirectory.getBookName()+"  下载完成");
    }

}
